package com.beiding.service.manager;

import com.beiding.dao.AuthorityDao;
import com.beiding.dao.UserDao;
import com.beiding.service.Authorities;
import com.google.common.collect.Sets;
import org.apache.commons.collections.collection.UnmodifiableCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Service
public class ManagerServiceImpl implements ManagerService{

    private RedisOperationsSessionRepository repository;

    private AuthorityDao authorityDao;

    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Autowired
    public void setAuthorityDao(AuthorityDao authorityDao) {
        this.authorityDao = authorityDao;
    }

    @Autowired
    public void setRepository(RedisOperationsSessionRepository repository) {
        this.repository = repository;
    }

    @Override
    public void register(String username, String authority) {
        authorityDao.add(username, authority);

        Map<String, ?> sessionMap = repository.findByPrincipalName(username);

        //找到申请人的Session,为其添加权限
        sessionMap.forEach((s, o) -> {
            addAuthority((Session) o, authority);

            //首先移除Session
           // repository.deleteById(s);

            //之后更新Session

            ((SessionRepository)repository).save((Session) o);

        });

    }



    //添加权限
    private void addAuthority(Session session, String auth) {


        SecurityContextImpl context = (SecurityContextImpl) session.getAttribute("SPRING_SECURITY_CONTEXT");

        GrantedAuthority authority = Authorities.of(auth);

        Authentication authentication = context.getAuthentication();

        HashSet<GrantedAuthority> set = Sets.newHashSet(authentication.getAuthorities());

        set.add(authority);

        Collection decorate = UnmodifiableCollection.decorate(set);

        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), decorate);

        context.setAuthentication(token);

        session.setAttribute("SPRING_SECURITY_CONTEXT", context);

    }


    @Override
    public Map<String, Set<String>> getAll() {
        return authorityDao.getAll();
    }

    @Override
    public void withdraw(String username, String authority) {

        //首先移除权限
        userDao.containerRemove(username, "authorities", Authorities.of(authority));

        authorityDao.remove(username, authority);

        //当用户被撤回权限的时候将它强制退出
        Map<String, ?> map = repository.findByPrincipalName(username);

        if (map != null)
            map.forEach((s, o) -> {
                repository.deleteById(s);
            });
    }
}
